#include "precompiled.h"
#include "AssetIOManager.h"
#include "CommonPools.h"
#include "AssetDefines.h"
#include "../include/rapidXML/rapidxml.hpp"
#include <sstream>
#include "Scenery.h"

using namespace rapidxml;
xml_document<> doc;

#define ASSET_PATH		"../worlds/"
#define MONKEY_STAT_YEA "../worlds/monkey_statue.yea"
#define MONKEY_MODEL	"../worlds/monkey.model"
#define TEST_WORLD		"../worlds/wtest.world"

AssetIOManager::AssetIOManager(void)
{
	//load_dot_yea( MONKEY_STAT_YEA );
	//load_dot_model( MONKEY_MODEL );
	//load_dot_world( TEST_WORLD );
}


AssetIOManager::~AssetIOManager(void)
{
}

void AssetIOManager::GetProcedural_Plane( Model& model ){
	ModelLoader::create_plane( model );
}


void AssetIOManager::load_model_to_pool( const char* path, const char* key ){
	Model *m = new Model();
	ModelLoader::load_myModel( path, *m );

	gs_geompool->add_model( std::string(key), *m );
}

void AssetIOManager::load_model_plane( const char* key ){
	Model *m = new Model();
	ModelLoader::create_plane( *m );

	gs_geompool->add_model( std::string(key), *m );
}


char* AssetIOManager::readFile(const char *filename) {
	FILE *file = fopen(filename, "r");
	if(file == NULL)
	{
		printError("ERROR", "AssetIOManager cannot open the file!");
		return 0;
	}
	int bytesinfile = filelength(fileno(file));
	char *buffer = (char*)malloc(bytesinfile+1);
	int bytesread = fread( buffer, 1, bytesinfile, file);
	buffer[bytesread] = 0; // Terminate the string with 0
	fclose(file);

	return buffer;
}


void split( vector<string> & theStringVector,  // Altered/returned value.
			const  string  & theString,
			const  string  & theDelimiter)
{
	assert( theDelimiter.size(), >, 0); // My own ASSERT macro.

	size_t  start = 0, end = 0;

	while ( end != string::npos)
	{
		end = theString.find( theDelimiter, start);

		// If at end, use length=maxLength.  Else use length=end-start.
		theStringVector.push_back( theString.substr( start,
			(end == string::npos) ? string::npos : end - start));

		// If at end, use start=maxSize.  Else use start=end+delimiter.
		start = (   ( end > (string::npos - theDelimiter.size()) )
			?  string::npos  :  end + theDelimiter.size());
	}
}

glm::ivec3 string_to_ivec3( std::string str ){
	std::vector<std::string> result;
	split( result, str, " " );

	return glm::ivec3(	atoi( result.at(0).c_str() ),
						atoi( result.at(1).c_str() ),
						atoi( result.at(2).c_str() ) );
}

// Removes all instance of a character from a string.
std::string remove_newlines_tabs_spaces( std::string s){
	for(int i=0;i<s.length();i++) {
		if(i<s.length() && s[i]=='\n') s.erase(s.begin()+i);
		 if(i<s.length() && s[i]=='\r') s.erase(s.begin()+i);
		 if(i<s.length() && s[i]=='\t') s.erase(s.begin()+i);
		 if(i<s.length() && s[i]==' ') s.erase(s.begin()+i);
		 //if(i<s.length() && s[i]=='\0') s.erase(s.begin()+i);
	}

	return s;
}
std::string remove_front_end( std::string s ){
	return s.substr( 1 , s.size() - 2 );
}
char easytolower(char in){
	if(in<='Z' && in>='A')
		return in-('Z'-'z');
	return in;
} 

// Add a scenery description to the vector of scenery descriptions.
void create_scenery_description( xml_node<> *child, std::queue<SCENERY_DESC> &scenery ){

	SCENERY_DESC ret;
	ret.yea_path="";

	std::vector<string> flagvec;

	if( child->first_node() == NULL )
		return;

	for( child;  child != NULL; child = child->next_sibling() ){
		// Grab out yea path.
		{
			xml_node<> *c1 = child->first_node();
			//printf("\t%s   value: %s\n", c1->name(), c1->value() );
			ret.yea_path = c1->value();
			ret.yea_path = remove_newlines_tabs_spaces( ret.yea_path );
			ret.yea_path = remove_front_end( ret.yea_path );
			ret.yea_path += ".yea";
		}
		child = child->next_sibling();

		// Grab our transforms.
		{
			xml_node<> *c1 = child->first_node();
			// trans.
			ret.transform._translation = string_to_ivec3(c1->value());
			ret.transform._position = glm::vec4(
				ret.transform._translation.x,
				ret.transform._translation.y,
				ret.transform._translation.z,
				1);
			c1 = c1->next_sibling();
			// rot.
			ret.transform._rotation = string_to_ivec3(c1->value());
			c1 = c1->next_sibling();
			// scale.
			ret.transform._scale = string_to_ivec3(c1->value());
			c1 = c1->next_sibling();
		}
		child = child->next_sibling();

		// Grab our flags.
		{
			for( xml_node<> *c1 = child->first_node() ; c1; c1 = c1->next_sibling() ){

				//printf("\t%s   value: %s\n", c1->name(), c1->value() );
				std::string flag = c1->value();
				flag = remove_newlines_tabs_spaces( flag );
				flag = remove_front_end( flag );
				std::transform(flag.begin(), flag.end(), flag.begin(), easytolower);

				flagvec.push_back( flag );

				//printf("Read flag: %s\n",flag.c_str());
			}
		}

		bool isStatic=false;
		bool isFlashable=false;
		for(int c = 0; c < flagvec.size(); c++ ){
			if( flagvec.at( c ) == "static" ){
				isStatic=true;
			}
			else if( flagvec.at( c ) == "flash" ){
				isFlashable=true;
			}
		}
		flagvec.clear();

		SCENERY_DESC tmp = {ret.yea_path, ret.transform, isStatic, isFlashable};
		scenery.push( tmp );
		ret.yea_path="";

		std::string bloop = (isStatic)?"true":"false";
		printf("obj: %s\tstatic: %s\n", tmp.yea_path.c_str(), bloop.c_str() );
	}

	

	return;
}

// Add a model description to the vector of model descriptions.
void create_model_description( xml_node<> *node, std::queue<DOT_MODEL_FILE> &model ){

	// Get the yea path.
	string path_model( node->value() );
	path_model = remove_newlines_tabs_spaces( path_model );
	node = node->next_sibling();

	// Get the key path.
	string key( node->value() );
	key = remove_newlines_tabs_spaces( key );
	node = node->next_sibling();

	DOT_MODEL_FILE dmf = {  key.c_str(), path_model.c_str() };
	model.push( dmf );
}

// Add a yea description to the queue of yea descriptions.
void create_yea_description( xml_node<> *node, std::queue<DOT_YEA_FILE> &yea ){
	// Get the yea path.
	string path_model( node->value() );
	path_model = remove_newlines_tabs_spaces( path_model );
	path_model += ".model";
	node = node->next_sibling();

	// Get the material path.
	/*string path_material( node->value() );
	path_material = path_material.substr(0, path_material.size()-1);
	path_material += ".material";
	node = node->next_sibling();*/

	DOT_YEA_FILE dyf = { path_model };
	yea.push( dyf );
}

void AssetIOManager::priv_load_dot_world( const char* path ){

	char* text = readFile( path );
	doc.parse<0>( text );

	xml_node<> *node = doc.first_node("world");

	// Enter the subnodes. Could be scenery. Could be npc.
	for (xml_node<> *child = node->first_node(); child; child = child->next_sibling())
	{
		std::string name(child->name());
		if( name == "scenery" )
			create_scenery_description( child->first_node(), tmp_scenery_desc );

	}
}
void AssetIOManager::load_dot_world( const char* path ){
	priv_load_dot_world( path );
	evaluate_world();
}
void AssetIOManager::load_dot_model( const char* path ){
	char* text = readFile( path );
	doc.parse<0>( text );

	xml_node<> *node = doc.first_node("model_path");

	if( node != NULL )
		create_model_description( node, tmp_model_desc );

	/*
	// Get the yea path.
	string path_model( node->value() );
	path_model = path_model.substr(0, path_model.size()-1);				// remove the newline character.
	path_model += ".yea";
	node = node->next_sibling();

	// Get the material path.
	string key( node->value() );
	key = key.substr(0, key.size()-1);
	node = node->next_sibling();

	printf("model path: %s\n",path_model.c_str());
	printf("key: %s\n",key.c_str());*/
}
void AssetIOManager::load_dot_yea( const char* path ){
	char* text = readFile( path );
	doc.parse<0>( text );

	xml_node<> *node = doc.first_node("model");

	create_yea_description( node, tmp_yea_desc );
/*
	// Get the yea path.
	string path_yea( node->value() );
	path_yea = path_yea.substr(0, path_yea.size()-1);				// remove the newline character.
	path_yea += ".yea";
	node = node->next_sibling();

	// Get the material path.
	string path_material( node->value() );
	path_material = path_material.substr(0, path_material.size()-1);
	path_material += ".material";
	node = node->next_sibling();

	printf(".yea path: %s\n",path_yea.c_str());
	printf(".material path: %s\n",path_material.c_str());*/
}

void AssetIOManager::evaluate_world(){
	while( !tmp_scenery_desc.empty() ){
		SCENERY_DESC sd = tmp_scenery_desc.front();
		tmp_scenery_desc.pop();

		evaluate_scenery_desc( sd );
	}
}

void AssetIOManager::evaluate_scenery_desc( SCENERY_DESC &sd ){
	// Load the descriptions .yea file.
	std::string yea_path( ASSET_PATH + sd.yea_path );
	load_dot_yea( yea_path.c_str() );

	if( !tmp_yea_desc.empty() ){
		DOT_YEA_FILE dyf = tmp_yea_desc.front();
		tmp_yea_desc.pop();
		std::string model_path( ASSET_PATH + dyf.model_path );
		printf(	"%s\n", model_path.c_str() );
		load_dot_model( model_path.c_str() );

		// Load the yea descriptions model into the model_pool if it does
		//	not already exist there.
		DOT_MODEL_FILE dmf = tmp_model_desc.front();
		tmp_model_desc.pop();

		if( !gs_geompool->isPooled( dmf.key ) ){
			std::string model_path = dmf.path;
			load_model_to_pool( model_path.c_str(), dmf.key.c_str() );
		}
		
		// Load the yea descriptions material.
		
		// Create the world scenery order.
		WORLD_SCENERY_ORDER wso = { dmf.key, sd.transform, sd.isStatic, sd.isFlashable };
		world_scenery_orders.push( wso );
	}
}


void AssetIOManager::Get_WorldSceneOrder( std::queue<WORLD_SCENERY_ORDER> &ref_wso_q ){
	ref_wso_q = world_scenery_orders;

	if( !tmp_scenery_desc.empty() )
		printf("tmp scenery desc not cleared\n");
	if( !tmp_model_desc.empty() )
		printf("tmp model desc not cleared\n");
	if( !tmp_yea_desc.empty() )
		printf("tmp yea desc not cleared\n");
}